package impl

import (
	"bytes"
	bucketService "gitee.com/kordar/bucket/service"
	util2 "gitee.com/kordar/bucket/util"
	"gitee.com/kordar/goadmin/admin/service"
	"github.com/gin-gonic/gin"
	logger "github.com/kordar/gologger"
	"github.com/kordar/goupload"
	"github.com/kordar/goutil"
	"github.com/spf13/cast"
	"gorm.io/gorm"
	"io"
	"labelsys/dataset/form"
	"path"
	"path/filepath"
	"strings"
	"time"
)

type DatasetUploadServiceImpl struct {
	db            *gorm.DB
	dictService   service.DictService
	bucketService bucketService.BucketService
}

func NewDatasetUploadServiceImpl(db *gorm.DB, bucketService bucketService.BucketService, dictService service.DictService) *DatasetUploadServiceImpl {
	return &DatasetUploadServiceImpl{db: db, bucketService: bucketService, dictService: dictService}
}

func (c *DatasetUploadServiceImpl) Upload(f form.UploadForm, ctx *gin.Context) (error, map[string]interface{}) {
	bucket, err2 := c.bucketService.GetBucket(int64(f.BucketID))
	if err2 != nil {
		return err2, nil
	}

	handler, err := util2.GetBucketHandler(bucket)
	if err != nil {
		return err, nil
	}

	fileHeader, err := ctx.FormFile("file")
	if err != nil {
		return err, nil
	}

	file, err := fileHeader.Open()
	if err != nil {
		return err, nil
	}
	defer file.Close()

	data, err := io.ReadAll(file)
	if err != nil {
		return err, nil
	}

	// 获取后缀名
	ext := filepath.Ext(fileHeader.Filename)
	uri := ""
	filename := ""

	datasetId := cast.ToString(int64(f.DatasetID))
	if f.Type == "label" {
		uri, filename, err = c.putByLabel(ctx, handler, data, f.FileName, datasetId, ext)
		if err != nil {
			return err, nil
		}
	}

	if f.Type == "images" {
		uri, filename, err = c.putByImage(ctx, handler, data, datasetId, ext)
		if err != nil {
			return err, nil
		}
	}

	if f.Type == "chunk" {
		uri, filename, err = c.appendData(ctx, handler, data, datasetId, ext, f.Position, f.Path, f.FileName)
		if err != nil {
			return err, nil
		}
	}

	config := bucket.GetConfig()
	base := config["host"]
	if !strings.HasSuffix(base, "/") {
		base += "/"
	}

	return nil, map[string]interface{}{
		"url":      base + uri,
		"path":     uri,
		"filename": filename,
	}
}

func (c *DatasetUploadServiceImpl) putByLabel(ctx *gin.Context, handler goupload.BucketUploader, data []byte, filename string, datasetId string, ext string) (string, string, error) {
	uri := ""
	if filename != "" {
		uri = path.Join(datasetId, "label", filename)
	} else {
		filename = goutil.UUID() + ext
		uri = path.Join(datasetId, "label", filename)
	}

	err := handler.Put(ctx, uri, bytes.NewReader(data))
	if err != nil {
		return uri, filename, err
	}

	return uri, filename, nil
}

func (c *DatasetUploadServiceImpl) putByImage(ctx *gin.Context, handler goupload.BucketUploader, data []byte, datasetId string, ext string) (string, string, error) {
	uri := ""
	t := time.Now().Format("2006/01/02")
	filename := goutil.UUID() + ext
	uri = path.Join(datasetId, "images", t, filename)

	err := handler.Put(ctx, uri, bytes.NewReader(data))
	if err != nil {
		return uri, filename, err
	}

	return uri, filename, nil
}

func (c *DatasetUploadServiceImpl) appendData(ctx *gin.Context, handler goupload.BucketUploader, data []byte, datasetId string, ext string, position int, uri string, filename string) (string, string, error) {
	if uri == "" {
		t := time.Now().Format("2006/01/02")
		filename = goutil.UUID() + ext
		uri = path.Join(datasetId, "images", t, filename)
		err := handler.Put(ctx, uri, bytes.NewReader(data))
		if err != nil {
			return uri, filename, err
		}
		return uri, filename, nil
	}

	_, err := handler.Append(ctx, uri, position, bytes.NewReader(data))
	logger.Infof("Append %s to %s ---> %d --- %d", uri, filename, position, len(data))
	if err != nil {
		logger.Errorf("err:%v", err)
		return uri, filename, err
	}

	return uri, filename, nil
}
